﻿namespace C_多线程示例
{
    internal class Program
    {
        // 共享资源：模拟一个计数器（多线程会同时操作它）
        private static int _sharedCounter = 0;

        // 锁对象：用于线程同步（确保同一时间只有一个线程访问共享资源）
        private static readonly object _lockObj = new object();

        static void Main(string[] args)
        {
            Console.WriteLine("===== 多线程教学演示 =====");
            Console.WriteLine("1. 先演示【无同步】的多线程操作（会出现竞态条件）");
            TestWithoutLock();

            Console.WriteLine("\n2. 再演示【有同步（锁）】的多线程操作（解决竞态条件）");
            TestWithLock();

            Console.WriteLine("\n演示结束，按任意键退出...");
            Console.ReadKey();
        }

        /// <summary>
        /// 测试无同步的多线程操作（会出现竞态条件）
        /// </summary>
        static void TestWithoutLock()
        {
            _sharedCounter = 0; // 重置计数器
            Console.WriteLine("\n【无锁情况】开始：");

            // 创建2个线程，同时执行IncrementCounter方法（无锁）
            Thread thread1 = new Thread(IncrementCounterWithoutLock);
            Thread thread2 = new Thread(IncrementCounterWithoutLock);

            // 启动线程
            thread1.Start();
            thread2.Start();

            // 等待两个线程执行完毕（避免主线程提前结束）
            thread1.Join();
            thread2.Join();

            // 输出结果（预期结果应为20000，但实际会小于20000，因为有竞态条件）
            Console.WriteLine($"【无锁情况】结束：最终计数器值 = {_sharedCounter}（应为20000，实际不符）");
        }

        /// <summary>
        /// 无锁的计数器递增方法（会导致竞态条件）
        /// </summary>
        static void IncrementCounterWithoutLock()
        {
            // 每个线程执行10000次递增
            for (int i = 0; i < 10000; i++)
            {
                // 危险操作：多线程同时读取、修改、写入共享变量
                // 可能出现：线程1读取值为100，线程2也读取100，两者都加1后写入101，导致少加1次
                _sharedCounter++;
            }
        }

        /// <summary>
        /// 测试有同步（锁）的多线程操作（解决竞态条件）
        /// </summary>
        static void TestWithLock()
        {
            _sharedCounter = 0; // 重置计数器
            Console.WriteLine("\n【有锁情况】开始：");

            // 创建2个线程，同时执行IncrementCounterWithLock方法（有锁）
            Thread thread3 = new Thread(IncrementCounterWithLock);
            Thread thread4 = new Thread(IncrementCounterWithLock);

            // 启动线程
            thread3.Start();
            thread4.Start();

            // 等待两个线程执行完毕
            thread3.Join();
            thread4.Join();

            // 输出结果（预期结果为20000，实际一致）
            Console.WriteLine($"【有锁情况】结束：最终计数器值 = {_sharedCounter}（符合预期20000）");
        }

        /// <summary>
        /// 有锁的计数器递增方法（解决竞态条件）
        /// </summary>
        static void IncrementCounterWithLock()
        {
            for (int i = 0; i < 10000; i++)
            {
                // lock语句：确保同一时间只有一个线程进入代码块
                // _lockObj是锁对象（必须是引用类型，且所有线程共享）
                lock (_lockObj)
                {
                    _sharedCounter++; // 此时只有一个线程操作共享变量，安全
                }
            }
        }
    }
}
